package com.ruoyi.web.controller.utils;

import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.framework.web.domain.server.Sys;
import io.minio.*;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.MinioException;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : SYGIS
 */

@Configuration
public class MinioFileUtil {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private MinioProperties minioProperties;

    private MinioClient minioClient;

    public final String filePath = "C:\\yndkdata\\";

    @Bean
    public MinioClient getClient() {
        String url = "http:" + minioProperties.getIp() + ":" + minioProperties.getPort();
        MinioClient minioClient = MinioClient.builder()
                .endpoint(url)    //两种都可以,这种全路径的其实就是下面分开配置一样的
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
        this.minioClient = minioClient;
        return minioClient;
    }

    public boolean checkBucketExist(String bucketName) throws Exception {
        if (!StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("检测桶的时候，桶名不能为空！");
        }
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    public void createBucket(String bucketName) throws Exception {
        if (!StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("创建桶的时候，桶名不能为空！");
        }
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }

    public void deleteBucket(String bucketName) throws Exception {
        if (!StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("删除桶的时候，桶名不能为空！");
        }
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    public void clearBucket(String bucketName) throws Exception {
        try {
            // 递归列举某个bucket下的所有文件，然后循环删除
            Iterable<Result<Item>> iterable = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .recursive(true)
                    .build());
            for (Result<Item> itemResult : iterable) {
                removeObject(bucketName,itemResult.get().objectName());
            }
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    public void removeObject(String buckectName,String fileName)throws Exception{
        try {
            //判断桶是否存在
            boolean res = checkBucketExist(buckectName);
            if (res) {
                //删除文件
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(buckectName).object(fileName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<Map<Object,Object>> listBucketFolderObjects(String buckectName,String folder) throws Exception{
        List<Map<Object,Object>> res = new ArrayList<>();
        try {
            // 检查'mybucket'是否存在。
            boolean found = checkBucketExist(buckectName);
            if (found) {
                // 列出'my-bucketname'里的对象
                Iterable<Result<Item>> listObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(buckectName).prefix(folder).build());
                for (Result<Item> result : listObjects) {
                    Item item = result.get();
//                    item.isDir() 是否是目录
                    Map<Object,Object> fileinfo = new HashMap<>();
                    fileinfo.put("isDir",item.isDir());
                    fileinfo.put("name",item.objectName().replaceAll(".shp","").replaceAll(".glb","").replaceAll(".glb",""));
                    fileinfo.put("fullname",item.objectName());
                    fileinfo.put("url","http://"+minioProperties.getIp()+":"+minioProperties.getPort()+"/"+buckectName+"/"+item.objectName());
                    String size = "";
                    if(item.size()<1024){
                        size = "1KB";
                    }else{
                        BigDecimal sizem = new BigDecimal(item.size()).divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                        if(sizem.compareTo(new BigDecimal(1024))>=0){
                            BigDecimal sizeg = sizem.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                            if(sizeg.compareTo(new BigDecimal(1024))>=0){
                                BigDecimal sizet = sizeg.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                                if(sizet.compareTo(new BigDecimal(1024))>=0){
                                    BigDecimal sizeb = sizet.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                                    size = sizeb+"T";
                                }else{
                                    size = sizet+"G";
                                }
                            }else{
                                size = sizeg+"M";
                            }
                        }else{
                            size = sizem+"KB";
                        }
                    }
                    fileinfo.put("size",size);
                    res.add(fileinfo);
                }
            } else {
                System.out.println("mybucket does not exist");
            }
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
        }
        return res;
    }

    public List<Map<Object,Object>> listBucketObjects(String buckectName) throws Exception{
        List<Map<Object,Object>> res = new ArrayList<>();
        try {
            // 检查'mybucket'是否存在。
            boolean found = checkBucketExist(buckectName);
            if (found) {
                // 列出'my-bucketname'里的对象
                Iterable<Result<Item>> listObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(buckectName).build());
                for (Result<Item> result : listObjects) {
                    Item item = result.get();
//                    item.isDir() 是否是目录
                    Map<Object,Object> fileinfo = new HashMap<>();
                    fileinfo.put("isDir",item.isDir());
                    fileinfo.put("name",item.objectName().replaceAll(".shp","").replaceAll(".glb","").replaceAll(".glb",""));
                    fileinfo.put("fullname",item.objectName());
                    fileinfo.put("url","http://"+minioProperties.getIp()+":"+minioProperties.getPort()+"/"+buckectName+"/"+item.objectName());
                    String size = "";
                    if(item.size()<1024){
                        size = "1KB";
                    }else{
                        BigDecimal sizem = new BigDecimal(item.size()).divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                        if(sizem.compareTo(new BigDecimal(1024))>=0){
                            BigDecimal sizeg = sizem.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                            if(sizeg.compareTo(new BigDecimal(1024))>=0){
                                BigDecimal sizet = sizeg.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                                if(sizet.compareTo(new BigDecimal(1024))>=0){
                                    BigDecimal sizeb = sizet.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                                    size = sizeb+"T";
                                }else{
                                    size = sizet+"G";
                                }
                            }else{
                                size = sizeg+"M";
                            }
                        }else{
                            size = sizem+"KB";
                        }
                    }
                    fileinfo.put("size",size);
                    res.add(fileinfo);
                }
            } else {
                System.out.println("mybucket does not exist");
            }
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
        }
        return res;
    }

    public void removeBuckectObject(String bucketName,String objectName) throws Exception {
        if (!StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("桶名不能为空！");
        }
        if (!StringUtils.hasLength(objectName)) {
            throw new RuntimeException("对象名不能为空！");
        }
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    public Boolean checkBucketFolderExist(String bucketName, String objectName, Boolean isDeep) {
        Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(isDeep).build());
        return results.iterator().hasNext();
    }

    public ObjectWriteResponse createBucketFolder(String bucketName, String folderName) throws Exception {
        if (!checkBucketExist(bucketName)) {
            throw new RuntimeException("必须在桶存在的情况下才能创建文件夹");
        }
        if (!StringUtils.hasLength(folderName)) {
            throw new RuntimeException("创建的文件夹名不能为空");
        }
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(folderName + "/")
                .stream(new ByteArrayInputStream(new byte[0]), 0, 0)
                .build();
        ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs);
        return objectWriteResponse;
    }

    public Boolean deleteBucketFolder(String bucketName, String objectName, Boolean isDeep) {
        if (!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(objectName)) {
            throw new RuntimeException("删除文件夹的时候，桶名或文件名不能为空！");
        }
        try {
            ListObjectsArgs args = ListObjectsArgs.builder().bucket(bucketName).prefix(objectName + "/").recursive(isDeep).build();
            Iterable<Result<Item>> listObjects = minioClient.listObjects(args);
            listObjects.forEach(objectResult -> {
                try {
                    Item item = objectResult.get();
                    minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(item.objectName()).build());
                } catch (Exception e) {
                    logger.info("删除文件夹中的文件异常", e);
                }
            });
            return true;
        } catch (Exception e) {
            logger.info("删除文件夹失败");
            return false;
        }
    }

    public boolean uploadPath(String filePath, String bucketName) throws Exception {
        File file = new File(filePath);
        if (!file.isFile()) {
            throw new RuntimeException("上传文件为空，请重新上传");
        }
        if (!this.checkBucketExist(bucketName)) {
            throw new RuntimeException("当前操作的桶不存在！");
        }
        String minioFilename = file.getName();//获取文件名称
//        UUID.randomUUID().toString() + "_" +
        String fileType = minioFilename.substring(minioFilename.lastIndexOf(".") + 1);
        minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(minioFilename)//文件存储在minio中的名字
                        .filename(filePath)//上传本地文件存储的路径
                        .contentType(fileType)//文件类型
                        .build());
        return this.getBucketFileExist(minioFilename, bucketName);
    }

    public boolean getBucketFileExist(String objectName, String bucketName) throws Exception {
        if (!StringUtils.hasLength(objectName) || !StringUtils.hasLength(bucketName)) {
            throw new RuntimeException("检测文件的时候，文件名和桶名不能为空！");
        }
        try {
            // 判断文件是否存在
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()) &&
                    minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()) != null;
            return exists;
        } catch (ErrorResponseException e) {
            logger.info("文件不存在 ! Object does not exist");
            return false;
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    public void uploadFile() throws Exception{
        try {
            // Create a minioClient with the MinIO server playground, its access key and secret key.
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint("http://111.229.29.129:9000")
                            .credentials("minioadmin", "minioadmin")
                            .build();
            String bucket = "ynjt123455555";
            // Make 'asiatrip' bucket if not exist.
            boolean found =
                    minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!found) {
                // Make a new bucket called bucket.
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            } else {
                System.out.println("Bucket " + bucket + " already exists.");
            }
            String fileName = "C:\\SYGIS\\test.txt";
            String objectName = "test.txt";
            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectName)
                            .filename(fileName)
                            .build());
            System.out.println(
                    fileName + " is successfully uploaded as"
                            + objectName + " to bucket " + bucket + ".");
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
            System.out.println("HTTP trace: " + e.httpTrace());
        }
    }

    public void uploadFiles() throws Exception{
        try {
            // Create a minioClient with the MinIO server playground, its access key and secret key.
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint("http://111.229.29.129:9000")
                            .credentials("minioadmin", "minioadmin")
                            .build();
            String bucket = "ynjt123455555";
            boolean found =
                    minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!found) {
                // Make a new bucket called bucket.
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            } else {
                System.out.println("Bucket " + bucket + " already exists.");
            }
            String filePath = "C:\\uploadtest";
            File folder = new File(filePath);
            if(folder.exists()&&folder.isDirectory()){
                File[] files = folder.listFiles();
                for (File file:files){
                    String objectName = file.getName();
                    String fileName = file.getAbsolutePath();
                    minioClient.uploadObject(
                            UploadObjectArgs.builder()
                                    .bucket(bucket)
                                    .object(objectName)
                                    .filename(fileName)
                                    .build());
                    System.out.println(
                            fileName + " is successfully uploaded as"
                                    + objectName + " to bucket " + bucket + ".");
                }
            }

        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
            System.out.println("HTTP trace: " + e.httpTrace());
        }
    }

    public String uploadFilesByStreamFolder(MultipartFile file,String bucket,String folder) throws Exception{
        String fileName = file.getOriginalFilename();
        String endpoint = "http://"+minioProperties.getIp()+":"+minioProperties.getPort()+"";
        try {
            // Create a minioClient with the MinIO server playground, its access key and secret key.
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(endpoint)
                            .credentials("minioadmin", "minioadmin")
                            .build();
            boolean found =
                    minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!found) {
                // Make a new bucket called bucket.
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            } else {
                System.out.println("Bucket " + bucket + " already exists.");
            }
            if(folder.equalsIgnoreCase(null)||folder.equalsIgnoreCase("null")){
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(bucket)
                                .object(fileName)
                                .stream(file.getInputStream(), file.getSize(), -1)
                                .build());
            }else {
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(bucket)
                                .object(folder+fileName)
                                .stream(file.getInputStream(), file.getSize(), -1)
                                .build());
            }

        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
            System.out.println("HTTP trace: " + e.httpTrace());
        }
        return endpoint + "/" + bucket + "/" + fileName;
    }

    public String uploadFilesByStream(MultipartFile file,String bucket) throws Exception{
        String fileName = file.getOriginalFilename();
        String endpoint = "http://"+minioProperties.getIp()+":"+minioProperties.getPort()+"";
        try {
            // Create a minioClient with the MinIO server playground, its access key and secret key.
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(endpoint)
                            .credentials("minioadmin", "minioadmin")
                            .build();
            boolean found =
                    minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!found) {
                // Make a new bucket called bucket.
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            } else {
                System.out.println("Bucket " + bucket + " already exists.");
            }
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .build());
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
            System.out.println("HTTP trace: " + e.httpTrace());
        }
        return endpoint + "/" + bucket + "/" + fileName;
    }

    public void getBucketPolicy(String buckect) throws Exception{
        String config =
                minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(buckect).build());
    }

    public void startBucketPolicy(String buckect,String createTime) throws Exception{
        String policyJson = "{\n" +
                "\"Version\":\"2012-10-17\",\n" +  // 创建时间吻合
                "\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\n" +
                "\"Action\":[\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\",\"s3:GetBucketLocation\"],\n" +
                "\"Resource\":[\"arn:aws:s3:::"+buckect+"\"]},\n" +
                "{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::"+buckect+"/*\"]}]}";
        minioClient.setBucketPolicy(
                SetBucketPolicyArgs.builder().bucket(buckect).config(policyJson).build());
        String config =
                minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(buckect).build());
    }

    public void stopBucketPolicy(String buckect) throws Exception{
        String policyJson = "{\n" +
                "    \"Version\": \"2012-10-17\",\n" +
                "    \"Statement\": []\n" +
                "}";
        minioClient.setBucketPolicy(
                SetBucketPolicyArgs.builder().bucket(buckect).config(policyJson).build());
        String config =
                minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(buckect).build());
    }
}
